package com.yunyao.framework.audit;

import com.yunyao.common.constant.enums.AuditStatusEnums;
import com.yunyao.common.core.BaseContext;
import com.yunyao.common.core.UserInfoRequest;
import com.yunyao.common.dto.audit.AuditFlowTypeEnums;
import com.yunyao.common.dto.audit.AuditResultEnums;
import com.yunyao.common.dto.audit.CreateAuditFlowDto;
import com.yunyao.common.exception.AuditException;
import com.yunyao.common.exception.BusinessException;
import com.yunyao.common.web.enums.ResultMsgEnum;
import com.yunyao.dao.model.*;
import com.yunyao.dao.service.bamu.*;
import com.yunyao.framework.dto.purchase.PurchaseContractApprovalDto;
import com.yunyao.framework.service.systemtwo.ContractService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.validation.constraints.NotBlank;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;

/**
 * @author xingjishuai
 * @date 2024-08-01
 */
@Slf4j
@Component
public class PurchaseContractAuditHandle extends AbstractAuditFlowHandle {
    @Autowired
    private IBamuPurchaseContractService iBamuPurchaseContractService;
    @Autowired
    private IBamuContractMaterialService iBamuContractMaterialService;
    @Autowired
    private IBamuContractWirePayService iBamuContractWirePayService;
    @Autowired
    private IBamuContractNodePayService iBamuContractNodePayService;
    @Resource
    private ContractService contractService;
    @Resource
    private IBamuPurchaseContractPrePaymentService purchaseContractPrePaymentService;

    /**
     * 提交采购合同审批
     *
     * @param bizId 业务ID，用于查询具体的采购合同信息
     * @throws AuditException 审批异常，当审批流程创建或更新过程中出现错误时抛出
     */
    @Transactional(rollbackFor = Exception.class)
    public void submit(String bizId) throws AuditException {
        // 根据业务ID获取采购合同信息，不包括已删除的记录
        BamuPurchaseContract purchaseContract = iBamuPurchaseContractService.getByIdNoDelete(bizId);
        // 获取采购合同名称，用于审批流程创建时的标识
        String contractName = purchaseContract.getContractName();
        // 获取采购合同状态，用于审批流程创建时的参数
        Integer status = purchaseContract.getStatus();
        // 从默认审核模型信息中获取采购合同ID，用于关联审批流程
        String purchaseContractId = defaultAuditModelInfo.getPurchaseContractId();

        try {
            // 检查提交的数据是否符合要求
            checkSubmitData(purchaseContract);
            // 创建审批流程实例
            CreateAuditFlowDto createAuditFlowDto = creatFlow(purchaseContractId,
                    AuditFlowTypeEnums.MODEL_NAME_PURCHASE_CONTRACT.getType(), bizId, contractName,
                    String.valueOf(status));

            // 更新采购合同信息，关联审批流程的实例ID、部署ID、模型方案信息ID和流程版本
            purchaseContract.setProcessInstanceId(createAuditFlowDto.getProcessInstanceId());
            purchaseContract.setDeploymentId(createAuditFlowDto.getDeploymentId());
            purchaseContract.setModelSchemeInfoId(createAuditFlowDto.getModelSchemeInfoId());
            purchaseContract.setProcessVersion(createAuditFlowDto.getProcessVersion());

            // 设置采购合同的审批状态为“审批中”
            purchaseContract.setAuditStatus(String.valueOf(AuditStatusEnums.AUDIT.getType()));
            // 更新采购合同信息
            iBamuPurchaseContractService.updateById(purchaseContract);
            //

        } catch (Exception e) {
            // 记录日志，并抛出审批异常
            log.error("采购合同submit approval error", e);
            throw new AuditException(e.getMessage());
        }
    }

    /**
     * 添加采购合同预收款
     * @param purchaseContract
     * @param contractType
     */
    private void addContractPrePayment(BamuPurchaseContract purchaseContract, @NotBlank String contractType) {
        BamuContractNodePay nodePay = contractService.findByContractIdStatus(purchaseContract.getId(), "0");
        if (nodePay == null) {
            log.info("根据合同ID没有找到对应的付款节点信息,合同ID:{}", purchaseContract.getId());
            return;
        }
        UserInfoRequest userInfo = BaseContext.getUserInfo();
        BamuPurchaseContractPrePayment dto = new BamuPurchaseContractPrePayment();
        dto.setContractId(purchaseContract.getId());
        dto.setContractNo(purchaseContract.getContractNo());
        dto.setContractName(purchaseContract.getContractName());
        dto.setContractType(contractType);
        dto.setProjectId(purchaseContract.getProjectId());
        dto.setProjectName(purchaseContract.getProjectName());
        dto.setProjectDeptId(purchaseContract.getProjectDeptId());
        dto.setProjectDeptName(purchaseContract.getProjectDeptName());
        dto.setProjectAddress(purchaseContract.getProjectAddress());
        dto.setSupplierDeptId(purchaseContract.getSupplierDeptId());
        dto.setSupplierDeptName(purchaseContract.getSupplierDeptName());
        dto.setSupplierCategoryId(purchaseContract.getSupplierCategoryId());
        dto.setSupplierCategoryName(purchaseContract.getSupplierCategoryName());
        dto.setSupplierCategoryName(purchaseContract.getSupplierCategoryName());

        dto.setContractPrePaymentRate(nodePay.getBackPayRate());
        dto.setContractPrePaymentDay(nodePay.getNatureDay());
        //数据库为null 0  暂且为0
        dto.setContractPrePaymentDayType(0);
        //合同预收款金额
        dto.setContractPrePaymentPrice(purchaseContract.getContractTotalPrice().multiply(nodePay.getBackPayRate()));
        //todo 暂时给最新日期
        dto.setContractPrePaymentDate(new Date());
        //真实付款金额
        dto.setContractRealPaymentPrice(purchaseContract.getContractTotalRealPrice());
        dto.setContractNum(purchaseContract.getContractNum());
        dto.setContractTotalPrice(purchaseContract.getContractTotalPrice());
        dto.setContractTotalRealPrice(purchaseContract.getContractTotalRealPrice());
        //合同汇款总金额-可能存在误差
        dto.setContractBackPrice(purchaseContract.getContractTotalPrice());
        //结算单文件
        dto.setReconciliationSettlementFile(purchaseContract.getContractFile());
        //对账结算说明
        dto.setReconciliationSettlementMark(purchaseContract.getMark());
        dto.setCreatedAt(new Date());
        dto.setCreatedBy(userInfo.getRealName());
        dto.setCreateDept(userInfo.getDeptId());
        dto.setStatus(1);
        dto.setTenantId(purchaseContract.getTenantId());
        dto.setAuditStatus(purchaseContract.getAuditStatus());
        dto.setProcessInstanceId(purchaseContract.getProcessInstanceId());
        dto.setModelSchemeInfoId(purchaseContract.getModelSchemeInfoId());
        dto.setDeploymentId(purchaseContract.getDeploymentId());
        dto.setProcessVersion(purchaseContract.getProcessVersion());
        //付款方式
        dto.setPaymentMethod(null);
        dto.setContractMethod(purchaseContract.getContractMethod());
        dto.setPurchaseDeptId(purchaseContract.getPurchaseDeptId());
        dto.setPurchaseDeptName(purchaseContract.getPurchaseDeptName());
        dto.setCheckMark(purchaseContract.getMark());
        dto.setCheckFile(purchaseContract.getContractFile());
        //开票状态
        dto.setReceiptStatus("0");
        //回款金额
        dto.setReceivePrice(BigDecimal.ZERO);
        //结余金额
        dto.setBalanceAmount(BigDecimal.ZERO);
        purchaseContractPrePaymentService.add(dto);
        log.info("采购合同预收款生成成功!");
    }


    /**
     * 审批采购合同
     *
     * @param approvalDto 包含采购合同审批信息的数据传输对象
     * @throws AuditException 如果审批过程中发生异常，则抛出审批异常
     */
    @Transactional(rollbackFor = Exception.class)
    public void approval(PurchaseContractApprovalDto approvalDto) throws AuditException {
        try {
            // 提取业务ID和审批结果
            String bizId = approvalDto.getId();
            Boolean auditResult = approvalDto.getAuditResult();
            // 根据审批结果生成对应的审批状态字符串
            String auditResultStr = auditResult ? AuditResultEnums.AGREE.getKey() :
                    AuditResultEnums.REJECT.getKey();
            // 通过业务ID获取采购合同详情，注意：此处不会删除数据
            BamuPurchaseContract purchaseContract =
                    iBamuPurchaseContractService.getByIdNoDelete(bizId);
            // 检查采购合同是否可以审批
            checkApprovalData(purchaseContract);
            // 执行流程，并根据审批结果和相关信息进行流程控制
            boolean isEnd = executeFlow(purchaseContract.getProcessInstanceId(),
                    purchaseContract.getDeploymentId(), auditResultStr,
                    approvalDto.getAuditResultMsg(), approvalDto.getAuditFileList());
            // 如果流程未结束，则直接返回，不进行后续操作
            if (!isEnd) {
                log.error("审批合同，审批流程未结束");
                return;
            }
            // 根据审批结果设置采购合同的审批状态
            if (auditResult) {
                purchaseContract.setAuditStatus(String.valueOf(AuditStatusEnums.AUDIT_SUCCESS.getType()));
                //添加采购合同预收款
                log.info("开始生成采购合同预收款---start");
                addContractPrePayment(purchaseContract, "1");
                log.info("开始生成采购合同预收款---end");
            } else {
                purchaseContract.setAuditStatus(String.valueOf(AuditStatusEnums.AUDIT_REJECT.getType()));
            }
            // 更新采购合同的审批状态
            iBamuPurchaseContractService.updateById(purchaseContract);
        } catch (Exception e) {
            // 记录审批过程中的异常错误
            log.error("采购合同 approval error", e);
            // 抛出审批异常，将异常信息传递给上层调用者
            throw new AuditException(e.getMessage());
        }
    }

    private void checkApprovalData(BamuPurchaseContract purchaseContract) throws AuditException {
        if (Objects.isNull(purchaseContract)) {
            throw new AuditException(ResultMsgEnum.NO_DATA);
        }
        String auditStatus = purchaseContract.getAuditStatus();
        if (AuditStatusEnums.AUDIT.getType() != Integer.parseInt(auditStatus)) {
            throw new AuditException(ResultMsgEnum.SUBMIT_AUDIT_STATUS_ERROR);
        }
        String processInstanceId = purchaseContract.getProcessInstanceId();
        if (StringUtils.isBlank(processInstanceId)) {
            throw new AuditException("processInstanceId is null");
        }
        String deploymentId = purchaseContract.getDeploymentId();
        if (StringUtils.isBlank(deploymentId)) {
            throw new AuditException("deploymentId is null");
        }
    }

    public boolean userIsAuditButton(String schemeInfoId, String processInstanceId) {
        try {
            return isCheckAudit(schemeInfoId, processInstanceId);
        } catch (Exception e) {
            log.info("采购合同userIsAuditButton error:{}", e.getMessage());
            return false;
        }
    }

    /**
     * 检查提交的数据是否有效
     *
     * @param purchaseContract 采购合同对象，用于检查
     * @throws AuditException 如果数据无效或审核状态冲突，抛出审核异常
     */
    private void checkSubmitData(BamuPurchaseContract purchaseContract) throws AuditException {
        // 检查采购合同对象是否为空
        if (Objects.isNull(purchaseContract)) {
            // 如果为空，抛出异常，表示没有数据可供审核
            throw new AuditException(ResultMsgEnum.NO_DATA);
        }

        // 获取采购合同的审核状态
        String auditStatus = purchaseContract.getAuditStatus();
        // 检查审核状态是否处于互斥状态
        if (AuditStatusEnums.AUDIT.getType() == Integer.parseInt(auditStatus)
                || AuditStatusEnums.AUDIT_SUCCESS.getType() == Integer.parseInt(auditStatus)
//                && AuditStatusEnums.AUDIT_REJECT.getType() == Integer.parseInt(auditStatus)
        ) {
            // 如果审核状态相互冲突，抛出异常，表示提交的审核状态错误
            throw new AuditException(ResultMsgEnum.SUBMIT_AUDIT_STATUS_ERROR);
        }
        String id = purchaseContract.getId();
        BamuContractWirePay bamuContractWirePay = iBamuContractWirePayService.getByContractId(id);
        if (Objects.isNull(bamuContractWirePay)) {
            throw new AuditException("合同支付方式信息为空不可提交审核");
        }
        List<BamuContractNodePay> nodePayList = iBamuContractNodePayService.listByContractId(id);
        if (CollectionUtils.isEmpty(nodePayList)) {
            throw new AuditException("合同付款方式节点信息为空不可提交审核");
        }
        List<BamuContractMaterial> contractMaterialList =
                iBamuContractMaterialService.listByContractId(id);
        if (CollectionUtils.isEmpty(contractMaterialList)) {
            throw new AuditException("合同材料为空不可提交审核");
        }
    }

}
